package com.hdl.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson.JSONObject;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;

/**
 * 类名 ConfigurationCenter
 * 描述 配置中心
 *
 * @author hedonglin
 * @version 1.0
 * @date 2020/6/18 14:07
 */
@Component
public class ConfigurationCenter {
    @Autowired(required = false)
    private DataSourceProperties dataSourceProperties;

    @Autowired
    private DefaultListableBeanFactory defaultListableBeanFactory;

    public static final String CONFIG_CENTER_DATASOURCE = "configCenterDatasource";

    /**
     * 配置中心ZK节点
     */
    public static final String DATABASE_CONFIGURATION = "/database_configuration";

    @Autowired(required = false)
    private CuratorFramework zkClient;

    public void watchConfigCenterNode() {
        // 首先从zookeeper中获取，如果没获取到，从本地获取，并存入zookeeper中
        if (zkClient != null) {
            try {
                // 获取配置节点
                Stat stat = zkClient.checkExists().forPath(DATABASE_CONFIGURATION);
                if (stat == null) {
                    if (dataSourceProperties != null) {
                        zkClient.create().forPath(DATABASE_CONFIGURATION, JSONObject.toJSONBytes(dataSourceProperties));
                    } else {
                        throw new RuntimeException("请先配置数据源");
                    }
                }
                // 获取节点数据
                byte[] data = zkClient.getData().usingWatcher(new Watcher() {
                      @Override
                      public void process(WatchedEvent watchedEvent) {
                          if (watchedEvent.getType() == Event.EventType.NodeDataChanged) {
                              System.out.println("数据库连接信息变化通知");
                              // 继续监听自己，并处理业务逻辑
                              watchConfigCenterNode();
                          }
                      }
                  }
                ).forPath(DATABASE_CONFIGURATION);
                // 解析出新的数据
                DataSourceProperties properties = JSONObject.parseObject(data, DataSourceProperties.class);
                DruidDataSource druidDataSource = setDataSourceByProperties(properties);
                // 配置中心
                boolean exist = defaultListableBeanFactory.containsBeanDefinition(ConfigurationCenter.CONFIG_CENTER_DATASOURCE);
                if (exist) {
                    // 移除后重新创建
                    defaultListableBeanFactory.removeBeanDefinition(ConfigurationCenter.CONFIG_CENTER_DATASOURCE);
                    registerDataSource(druidDataSource);
                } else {
                    // 创建
                    registerDataSource(druidDataSource);
                }
                System.out.println("配置为配置中心数据源信息，信息为：" + properties);
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("zookeeper配置中心异常");
            }
        } else {
            if (dataSourceProperties == null) {
                throw new RuntimeException("请先配置数据源");
            }
            DruidDataSource druidDataSource = setDataSourceByProperties(dataSourceProperties);
            System.out.println("配置为本地数据源信息，信息为：" + dataSourceProperties);
            registerDataSource(druidDataSource);
        }

    }

    /**
     * 手动注册数据源为Bean
     * @param druidDataSource
     */
    private void registerDataSource(DruidDataSource druidDataSource) {
        // 生成Bean定义构建器
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DataSource.class);
        // 根据构建器获取BeanBeanDefinition，并注册
        defaultListableBeanFactory.registerBeanDefinition(ConfigurationCenter.CONFIG_CENTER_DATASOURCE, builder.getBeanDefinition());
        // 将对象注册到单例池中
        defaultListableBeanFactory.registerSingleton(ConfigurationCenter.CONFIG_CENTER_DATASOURCE, druidDataSource);
    }

    /**
     * 设置数据源参数
     * @param properties
     * @return
     */
    private DruidDataSource setDataSourceByProperties(DataSourceProperties properties) {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(properties.getDriverClassName());
        druidDataSource.setUrl(properties.getJdbcUrl());
        druidDataSource.setUsername(properties.getUsername());
        druidDataSource.setPassword(properties.getPassword());
        druidDataSource.setMaxActive(properties.getMaxActive());
        druidDataSource.setMaxIdle(properties.getMaxIdle());
        return druidDataSource;
    }
}
